Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

What swap is called when using std::swap?

201 views
Skip to first unread message

Niels Dekker (no reply address)

unread,
Jul 19, 2006, 3:05:12 AM7/19/06
to
When calling swap as follows (as recommanded in Effective C++, 3rd
Edition, by Scott Meyers), what swap is chosen to be called?
using std::swap;
swap(a, b);

Suppose there is a global ::swap function provided, whose parameter type
matches closer to the type of a and b than any of the std::swap
overloads does. Will this ::swap be called, or is std::swap still
preferred? I ask this because the compilers I tried disagree! So will
any of the ::swap functions I defined down below be called in the
following main()?

#include <algorithm>
struct Foo {};

void swap(int &, int &) {}
void swap(Foo &, Foo &) {}
template<typename T> void swap(T*&, T*&) {}

int main()
{
using std::swap;

int i1, i2;
swap(i1, i2);

int *ptr1, *ptr2;
swap(ptr1, ptr2);

Foo foo1, foo2;
swap(foo1, foo2);

Foo *foo_ptr1, *foo_ptr2;
swap(foo_ptr1, foo_ptr2);
}

To my surprise, MSVC++ 8.0 prefers to call std::swap for int and int*.
It only calls ::swap for Foo and Foo*. But GNU g++ 3.4.4 surprises me
even more, as it never calls any of my ::swap overloads at all, and
always prefers calling std::swap instead! So what's the Standard
compliant way?


Kind regards

Niels Dekker
xs4all.nl/~nd/dekkerware

werasm

unread,
Jul 19, 2006, 8:18:45 AM7/19/06
to

Niels Dekker (no reply address) wrote:
> When calling swap as follows (as recommanded in Effective C++, 3rd
> Edition, by Scott Meyers), what swap is chosen to be called?
> using std::swap;
> swap(a, b);
>
> Suppose there is a global ::swap function provided, whose parameter type
> matches closer to the type of a and b than any of the std::swap
> overloads does. Will this ::swap be called, or is std::swap still
> preferred?

"using std::swap" would mean std::swap would be taken into
consideration when establishing the initial overload set. Usually, when
all aspects of overload resolution are equal, non-templates would be
preferred.

> #include <algorithm>
> struct Foo {};
>
> void swap(int &, int &) {}
> void swap(Foo &, Foo &) {}
> template<typename T> void swap(T*&, T*&) {}
>
> int main()
> {
> using std::swap;
>
> int i1, i2;
> swap(i1, i2);


I would call you swap(int&,int&) a perfect match here, and would put my
money on it being called everytime.


>
> int *ptr1, *ptr2;
> swap(ptr1, ptr2);

Your (template) version of swap is more specialized than the std::swap
- therefore it should be called here (I'm using SGI std::swap as
reference).

SGI...
template <class Assignable>
void swap(Assignable& a, Assignable& b);
...
It may be possible that other libs have more specialized swaps for
pointers. If this is the case (IMO), you should get ambiguities.

>
> Foo foo1, foo2;
> swap(foo1, foo2);

void swap(Foo &, Foo &), for the same reason - non-templates preferred.

>
> Foo *foo_ptr1, *foo_ptr2;
> swap(foo_ptr1, foo_ptr2);

Once again, your template version is more specialized.


> }
>
> To my surprise, MSVC++ 8.0 prefers to call std::swap for int and int*.

This is surprising IMhO, and would like someone to educate me too in
the event of me being wrong :-). I don't consider the compilers std
compliant, but I may be wrong.

Kind regards,

Werner

Howard Hinnant

unread,
Jul 19, 2006, 10:35:23 AM7/19/06
to
In article <44BDD9A8...@this.is.invalid>,

swap(i1, i2);

This calls std::swap. The function-local using declaration hides the
global swaps from ordinary lookup, but not ADL. The global swap isn't
found via ADL because there is no namespace associated with int.

swap(ptr1, ptr2);

This calls std::swap, for the same reasons as the previous call.

swap(foo1, foo2);

This calls ::swap(Foo&,Foo&). Ordinary lookup does not find this, but
ADL kicks in and searches the namespace associated with Foo (global).

swap(foo_ptr1, foo_ptr2);

This calls ::swap(T*&, T*&). Ordinary lookup does not find this, but
ADL kicks in and searches the namespace associated with Foo (global).

An interesting experiment is to move the using declaration to namespace
scope (above main), and reexamine.

-Howard

werasm

unread,
Jul 19, 2006, 11:28:19 AM7/19/06
to

Howard Hinnant wrote:

> This calls std::swap. The function-local using declaration hides the
> global swaps from ordinary lookup, but not ADL. The global swap isn't
> found via ADL because there is no namespace associated with int.

Interesting. I was under the impression that because main is defined in
the global scope, using declarations in it become associated with the
global scope. This is obviously wrong - it becomes associated with the
function scope, which takes precedence over the global scope. Therefore
the initial overload set considered is that within function scope
(which is what can be found via ADL and what is part of function scope
by local using). I thought I would learn by taking the shot :-)


> An interesting experiment is to move the using declaration to namespace
> scope (above main), and reexamine.

Quick guess is that it will work iaw. with my original thought, as the
global swaps and std::swap would form part of the same overload set,
and the OP's swaps are more specialized?

Kind regards,

W

Niels Dekker (no reply address)

unread,
Jul 20, 2006, 4:44:03 PM7/20/06
to
Thanks very much to you both, Werner and Howard!

> int main()
> {
> using std::swap;
>
> int i1, i2;
> swap(i1, i2);

Howard Hinnant wrote:


> This calls std::swap. The function-local using declaration hides the
> global swaps from ordinary lookup, but not ADL. The global swap isn't
> found via ADL because there is no namespace associated with int.


It's clear to me now :-)


Kind regards,

Niels

0 new messages